/**
*		@file Follows.cpp
*		@brief Follows class
*
*		@author Zhou Nan
*
*		@date 1/25/2012
*/
#include "Follows.h"
vector<StmtSet>	Follows::follows_table_;
vector<StmtSet>	Follows::follows_table_t_;

vector<StmtSet>	Follows::follows_adv_table_;
vector<StmtSet>	Follows::follows_adv_table_t_;

StmtSet			Follows::follows_has_s0_;
StmtSet			Follows::follows_has_0s_;
bool			Follows::follows_has_00_;

void Follows::RebuildFollows()
{
	for(int i = 0; i < StmtTable::GetSize(); i++){
		StmtSet new_follows_r(StmtTable::GetSize(),false);
		TNode* traverser = StmtTable::GetStmtTNode(i+1)->right_sibling;
		if( traverser != NULL )
			new_follows_r[traverser->stmt_num - 1] = true;
		follows_table_.push_back(new_follows_r);
	}
	for(int i = 0; i < StmtTable::GetSize(); i++){
		StmtSet new_follows_l(StmtTable::GetSize(),false);
		TNode* traverser = StmtTable::GetStmtTNode(i+1)->left_sibling;
		if( traverser != NULL )
			new_follows_l[traverser->stmt_num - 1] = true;
		follows_table_t_.push_back(new_follows_l);
	}

	for(int i = 0; i < StmtTable::GetSize(); i++){
		StmtSet new_adv_follows_r(StmtTable::GetSize(),false);
		TNode* traverser = StmtTable::GetStmtTNode(i+1)->right_sibling;
		while(traverser != NULL){
			new_adv_follows_r[traverser->stmt_num - 1] = true;
			traverser = traverser->right_sibling;
		}
		follows_adv_table_.push_back(new_adv_follows_r);
	}

	for(int i = 0; i < StmtTable::GetSize(); i++){
		StmtSet new_adv_follows_l(StmtTable::GetSize(),false);
		TNode* traverser = StmtTable::GetStmtTNode(i+1)->left_sibling;
		while(traverser != NULL){
			new_adv_follows_l[traverser->stmt_num - 1] = true;
			traverser = traverser->left_sibling;
		}
		follows_adv_table_t_.push_back(new_adv_follows_l);
	}

	follows_has_s0_.resize(StmtTable::GetSize(),false);
	follows_has_0s_.resize(StmtTable::GetSize(),false);
	follows_has_00_ = false;
	return;
}

void Follows::CompleteFollows()
{
	for( int i = 0; i < StmtTable::GetSize(); i++ )	follows_has_s0_[i] = IsAny<StmtSet>(follows_table_[i]);
	for( int i = 0; i < StmtTable::GetSize(); i++ )	follows_has_0s_[i] = IsAny<StmtSet>(follows_table_t_[i]);
	follows_has_00_ = IsAny<StmtSet>(follows_has_s0_);
	return;
}

/* TODO: comment */
StmtSet& Follows::GetFollowsRight(StmtNum stmt_num_left)
{
	return follows_table_[stmt_num_left - 1];
}

/* TODO: comment */
StmtSet& Follows::GetFollowsLeft(StmtNum stmt_num_right)
{
	return follows_table_t_[stmt_num_right - 1];
}

/* TODO: comment */
StmtSet& Follows::GetFollowsAdvRight(StmtNum stmt_num_left)
{
	return follows_adv_table_[stmt_num_left - 1];
}

/* TODO: comment */
StmtSet& Follows::GetFollowsAdvLeft(StmtNum stmt_num_right)
{
	return follows_adv_table_t_[stmt_num_right - 1];
}

/* TODO: comment */
bool Follows::IsFollows(StmtNum stmt_num_left, StmtNum stmt_num_right)
{
	if( stmt_num_left > StmtTable::GetSize() || stmt_num_right > StmtTable::GetSize() )
		return false;
	if( stmt_num_left == 0 )
	{
		if( stmt_num_right == 0 )
			return follows_has_00_;
		else
			return follows_has_0s_[stmt_num_right - 1];
	}
	else
	{
		if( stmt_num_right == 0 )
			return follows_has_s0_[stmt_num_left - 1];
		else
			return follows_table_[stmt_num_left - 1][stmt_num_right - 1];
	}
}

/* TODO: comment */
bool Follows::IsFollowsAdv(StmtNum stmt_num_left, StmtNum stmt_num_right)
{
	if( stmt_num_left > StmtTable::GetSize() || stmt_num_right > StmtTable::GetSize() )
		return false;
	if( stmt_num_left == 0 )
	{
		if( stmt_num_right == 0 )
			return follows_has_00_;
		else
			return follows_has_0s_[stmt_num_right - 1];
	}
	else
	{
		if( stmt_num_right == 0 )
			return follows_has_s0_[stmt_num_left - 1];
		else
			return follows_adv_table_[stmt_num_left - 1][stmt_num_right - 1];
	}
}

string Follows::ToString()
{
	stringstream ss_result;
	ss_result << "Follows :\n";
	for( int i = 0; i < StmtTable::GetSize(); i++ )
	{
		ss_result << (i+1)  << " : ";
		if( StmtTable::GetStmtTNode(i+1)->right_sibling != NULL )
			ss_result << StmtTable::GetStmtTNode(i+1)->right_sibling->stmt_num <<" ";
		ss_result << "\n";
	}
	return ss_result.str();
}